package com.showcai.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.showcai.log.LogFactory;
import com.showcai.myRunTime.MyRunTimeExcption;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description: (带LOGO二维码)
 */
public class QRCodeUtil

{
    protected Logger logger = LogFactory.getLogger(getClass());
    private static final int QRCOLOR = 0xFF000000;   //默认是黑色
    private static final int BGWHITE = 0xFFFFFFFF;   //背景颜色(白色)



    public static final String IMG_FORMAT_JPG = "JPG";
    public static final String IMG_FORMAT_PNG = "PNG";


    public static void main(String[] args) throws WriterException
    {
        try
        {
             getLogoQRCode("http://www.feesoul.com/product/1510726960726001.html","http://wx.qlogo.cn/mmopen/Q3auHgzwzM4rib0L0WKibK9VRTvE0FhLdfXqh2rnicMkibPcsMxFqW7GBmYd8hqsrwb8rPI4C1Y1GTmKsks8ibKjMdA/0","jpg","d:/logo.jpg");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    /**
     * 生成带logo的二维码图片
     * @param qrUr 内容
     * @param logoPath LOGOG地址
     * @param format 二维码图片格式
     * @param filePath 已经生产的图片地址
     */
    public static void getLogoQRCode(String qrUr,String logoPath,String format,String filePath)
    {
//      String filePath = (javax.servlet.http.HttpServletRequest)request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png";
        //filePath是二维码logo的路径，但是实际中我们是放在项目的某个路径下面的，所以路径用上面的，把下面的注释就好
        //logoPath = "C:/Users/lutao/Pictures/0.jpg";
        String content = qrUr;
        try
        {
            QRCodeUtil zp = new QRCodeUtil();
            BufferedImage bim = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, zp.getDecodeHintType());
            if(StringUtils.isNotBlank(logoPath)){
                zp.addLogoStr_QRCode(bim, logoPath,new LogoConfig(),format,filePath);
            }else{
                File file = new File(filePath);
                if (!ImageIO.write(bim, format,file)) {
                    throw new IOException("Could not write an image of format "
                            + format + " to " + file);
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new MyRunTimeExcption(e.getMessage());
        }
    }
    /**
     * 生成不带logo的二维码图片
     * @param content 内容
     */
    public static BufferedImage getQRCode(String content)
    {
//      String filePath = (javax.servlet.http.HttpServletRequest)request.getSession().getServletContext().getRealPath("/") + "resources/images/logoImages/llhlogo.png";
        //filePath是二维码logo的路径，但是实际中我们是放在项目的某个路径下面的，所以路径用上面的，把下面的注释就好
        //logoPath = "C:/Users/lutao/Pictures/0.jpg";

        QRCodeUtil zp = new QRCodeUtil();
        BufferedImage bim = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, zp.getDecodeHintType());
        return bim;

    }
    public static int IsNetOrLocal (String path) throws SocketException {
        //如果src不以http开头，则是本地文件；若src以http开头，但是后面是localhost或者本机IP的话，也是本地文件了,否则就是网络文件
        //获取本机的IP地址,构造路径头
        StringBuffer header = new StringBuffer();
        Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
        while (en.hasMoreElements()) {
            NetworkInterface ni = en.nextElement();
            Enumeration<InetAddress> enAddr = ni.getInetAddresses();
            while (enAddr.hasMoreElements()) {
                header.append("http:/" + enAddr.nextElement());
                header.append("|");
            }
        }
        header.append("http://localhost");
        //header用来判断是否为"http://127.0.0.1或"http://192.168.1.235”或"http://localhost”
        System.out.println(header.toString());
        //用正则表达式和字符串的相关函数进行判断
        Pattern p = Pattern.compile(header.toString());
        Matcher m = p.matcher(path);
        if (m.find()) {//匹配是否为http开头的本地文件
            System.out.println("本地文件");
            return 1;
        } else if (path.indexOf("http://") != -1 || path.indexOf("https://") != -1) {//网络文件
            System.out.println("网络文件");
            return -1;
        } else {//否则就是本地文件
            System.out.println("本地文件");
            return 1;
        }
    }

    /**
     * 给二维码图片添加Logo
     *
     * @param
     * @param logoPic
     */
    public  String addLogoStr_QRCode(BufferedImage bim, String logoPic,LogoConfig logoConfig,String format,String filePath)
    {
        try
        {
           /**
             * 读取二维码图片，并构建绘图对象
             */
            BufferedImage image = bim;
            Graphics2D g = image.createGraphics();
            BufferedImage logo = null;
            /**
             * 读取Logo图片
             */
            if (IsNetOrLocal(logoPic) == -1){
                //网络文件
                logo = ImageIO.read(new URL(logoPic));
            }else{
                //本地文件
                logo = ImageIO.read(new File(logoPic));
            }
           /**
             * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
             */
            int widthLogo = logo.getWidth(null)>image.getWidth()*3/10?(image.getWidth()*3/10):logo.getWidth(null),
                    heightLogo = logo.getHeight(null)>image.getHeight()*3/10?(image.getHeight()*3/10):logo.getWidth(null);

            /**
             * logo放在中心
             */
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;
            /**
             * logo放在右下角
             *  int x = (image.getWidth() - widthLogo);
             *  int y = (image.getHeight() - heightLogo);
             */

            //开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);
            g.dispose();


            logo.flush();
            image.flush();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.flush();
            ImageIO.write(image, format, baos);

            //二维码生成的路径，但是实际项目中，我们是把这生成的二维码显示到界面上的，因此下面的折行代码可以注释掉
            //可以看到这个方法最终返回的是这个二维码的imageBase64字符串
            //前端用 <img src="data:image/png;base64,${imageBase64QRCode}"/>  其中${imageBase64QRCode}对应二维码的imageBase64字符串
            ImageIO.write(image, format, new File(filePath));
            String imageBase64QRCode =  Base64.encodeBase64URLSafeString(baos.toByteArray());
            baos.close();
            return imageBase64QRCode;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构建初始化二维码
     *
     * @param bm
     * @return
     */
    public BufferedImage fileToBufferedImage(BitMatrix bm)
    {
        BufferedImage image = null;
        try
        {
            int w = bm.getWidth(), h = bm.getHeight();
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE);
                }
            }

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return image;
    }

    /**
     * 生成二维码bufferedImage图片
     *
     * @param content
     *            编码内容
     * @param barcodeFormat
     *            编码类型
     * @param width
     *            图片宽度
     * @param height
     *            图片高度
     * @param hints
     *            设置参数
     * @return
     */
    public BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width, int height, Map<EncodeHintType, ?> hints)
    {
        MultiFormatWriter multiFormatWriter = null;
        BitMatrix bm = null;
        BufferedImage image = null;
        try
        {
            multiFormatWriter = new MultiFormatWriter();
            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
            bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);
            int w = bm.getWidth();
            int h = bm.getHeight();
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

            // 开始利用二维码数据创建Bitmap图片，分别设为黑（0xFFFFFFFF）白（0xFF000000）两色
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE);
                }
            }
        }
        catch (WriterException e)
        {
            e.printStackTrace();
        }
        return image;
    }

    /**
     * 设置二维码的格式参数
     *
     * @return
     */
    public Map<EncodeHintType, Object> getDecodeHintType()
    {
        // 用于设置QR二维码参数
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        // 设置QR二维码的纠错级别（H为最高级别）具体级别信息
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置编码方式
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        hints.put(EncodeHintType.MAX_SIZE, 350);
        hints.put(EncodeHintType.MIN_SIZE, 100);

        return hints;
    }
}


class LogoConfig
{
    // logo默认边框颜色
    public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;
    // logo默认边框宽度
    public static final int DEFAULT_BORDER = 2;
    // logo大小默认为照片的1/5
    public static final int DEFAULT_LOGOPART = 5;

    private final int border = DEFAULT_BORDER;
    private final Color borderColor;
    private final int logoPart;


    public LogoConfig()
    {
        this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);
    }

    public LogoConfig(Color borderColor, int logoPart)
    {
        this.borderColor = borderColor;
        this.logoPart = logoPart;
    }

    public Color getBorderColor()
    {
        return borderColor;
    }

    public int getBorder()
    {
        return border;
    }

    public int getLogoPart()
    {
        return logoPart;
    }
}


/* *//**
 * 给二维码图片添加Logo
 *
 * @param qrPic
 * @param logoPic
 *//*
    public void addLogo_QRCode(File qrPic, File logoPic, LogoConfig logoConfig)
    {
        try
        {
            if (!qrPic.isFile() || !logoPic.isFile())
            {
                System.out.print("file not find !");
                System.exit(0);
            }

            *//**
 * 读取二维码图片，并构建绘图对象
 *//*
            BufferedImage image = ImageIO.read(qrPic);
            Graphics2D g = image.createGraphics();

            *//**
 * 读取Logo图片
 *//*
            BufferedImage logo = ImageIO.read(logoPic);
            *//**
 * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
 *//*
            int widthLogo = logo.getWidth(null)>image.getWidth()*2/10?(image.getWidth()*2/10):logo.getWidth(null),
                    heightLogo = logo.getHeight(null)>image.getHeight()*2/10?(image.getHeight()*2/10):logo.getHeight(null);

            // 计算图片放置位置
            *//**
 * logo放在中心
 *//*
              int x = (image.getWidth() - widthLogo) / 2;
               int y = (image.getHeight() - heightLogo) / 2;
            *//**
 * logo放在右下角
 *//*
          *//*  int x = (image.getWidth() - widthLogo);
            int y = (image.getHeight() - heightLogo);*//*
            //开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();

            ImageIO.write(image, "jpg", new File("C:/Users/lutao/Pictures/log.jpg"));

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
*/
